import os
import sys
from math import  exp, log,fabs,pow
from itertools import  combinations
'''
    a1  : program1
    a2  : program2

    编写时间     ：2022-7-4
    编写人      ：吴卓成
    参考文献    ：Multiple‐attribute group decision‐making
                based on power Bonferroni operators of
                linguistic q‐rung orthopair fuzzy numbers
    DOI       ：
    attention :  The Power Average Operator 与此篇参考文献对于权重问题写法 存在不一致性，此处的融合算子对于WA，OWA两类参考
'''

from Utilities.AutoGetOperator.selectPackage import get_func

Operator_IVQ_ROFS=get_func(r'Operators/FunctionOperators/PowerAverageOperator.py','PowerAverageOperatorA')


class PowerBonferroniA(Operator_IVQ_ROFS):
    '''
    attention: 继承的类中对于Ti的是采取不带权重的公式，在写含权重的时候要重构
    self.get_ta（i_a） 是采取不带加权的计算 ，i_a是代表的是下角标
    self.a :对应公式法则中的A
    self.b :对应公式类的所B
    attention:  继承为了是利用的是基类的self.get_ta(i_a)

    '''



    def two_multil(self,conbina:tuple,res_t=None):
        '''

        :param a1:  索引下标
        :param a2:  索引下标
        :param res_t: 1+Ti的累和结果
        :return: 两个模糊数的计算结果
        '''
        a1,a2=conbina
        A=self.a
        B=self.b
        n=len(self.data_list)
        if res_t is None:
            raise TypeError("res_t is NUll")
        res_a1=self.pow(self.kmulti(self.data_list[a1],(((1+self.get_ta(a1))*n)/res_t)),A)
        res_a2=self.pow(self.kmulti(self.data_list[a2],(((1+self.get_ta(a2))*n)/res_t)),B)
        return self.multi(res_a1,res_a2)



    def getResult(self):
        res_t=0 #储存 （1+Ti）累和的值
        length_data=len(self.data_list)
        # （1 +Ti）的累和
        for index in range(length_data):
            res_t+=(self.get_ta(index)+1)
        select_sort=list(combinations(len(self.data_list),2))#二项式得到的每一个选择排列 eg [(5, 6), (5, 7), (5, 8), (6, 7), (6, 8), (7, 8)]
        select=iter(select_sort)
        value=self.two_multil(next(select),res_t)
        for it in select:
            temp = self.two_multil(it, res_t)
            value=self.add(value,temp)
        return self.pow(self.kmulti(value,1/(length_data*length_data-length_data)),1/(self.a+self.b))
class PowerBonferroniGA(Operator_IVQ_ROFS):
    def two_add(self,conbina:tuple,res_t=None):
        '''

        :param a1:  索引下标
        :param a2:  索引下标
        :param res_t: 1+Ti的累和结果
        :return: 两个模糊数的计算结果
        conbina:  二项式选择排序的一种结果，形式为（index1，index2）
        '''
        a1,a2=conbina
        A=self.a
        B=self.b
        n=len(self.data_list)
        if res_t is None:
            raise TypeError("res_t is NUll")
        res_a1=self.kmulti(self.pow(self.data_list[a1],(((1+self.get_ta(a1))*n)/res_t)),A)
        res_a2=self.kmulti(self.pow(self.data_list[a2],(((1+self.get_ta(a2))*n)/res_t)),B)
        return self.pow(self.add(res_a1,res_a2),1/(n*n-n))
    def getResult(self):
        res_t=0 #储存 （1+Ti）累和的值
        length_data=len(self.data_list)
        # （1 +Ti）的累和
        for index in range(length_data):
            res_t+=(self.get_ta(index)+1)
        select_sort=list(combinations(len(self.data_list),2))#二项式得到的每一个选择排列 eg [(5, 6), (5, 7), (5, 8), (6, 7), (6, 8), (7, 8)]
        select=iter(select_sort)
        value=self.two_add(next(select),res_t)
        for it in select:
            temp = self.two_add(it, res_t)
            value=self.multi(value,temp)
        return self.kmulti(value,1/(self.a+self.b))
class PowerBonferroniWGA(Operator_IVQ_ROFS):
    def get_ta(self, i_a, *waste1, **waste2):
        """
            function : 计算 TA ，需要调用 get_sup
            i_a      : 传入模糊数 ai 的下标 int
            *waste1  : 回收多余的输入参数
            **waste2 : 回收多余的输入键值对参数
            return   : T(ai) 的值
            attention:此处带权重的计算公式，索引重写这个函数
        """
        ta = 0
        # T(ai) = 累加wi * Sup(ai, aj)
        for j_a in range(len(self.data_list)):
            if j_a != i_a:         # 公式要求 i != j
                ta += self.get_sup(self.data_list[i_a], self.data_list[j_a])*self.weight_list[i_a]
        return ta
    def two_add(self,conbina:tuple,res_t=None):
        '''

        :param a1:  索引下标
        :param a2:  索引下标
        :param res_t: 1+Ti的累和结果
        :return: 两个模糊数的计算结果
        conbina:  二项式选择排序的一种结果，形式为（index1，index2）
        '''
        a1,a2=conbina
        A=self.a
        B=self.b
        n=len(self.data_list)
        if res_t is None:
            raise TypeError("res_t is NUll")
        res_a1=self.kmulti(self.pow(self.data_list[a1],(((1+self.get_ta(a1))*n*self.weight_list[a1])/res_t)),A)
        res_a2=self.kmulti(self.pow(self.data_list[a2],(((1+self.get_ta(a2))*n*self.weight_list[a2])/res_t)),B)
        return self.pow(self.add(res_a1,res_a2),1/(n*n-n))
    def getResult(self):
        res_t=0 #储存 （1+Ti）累和的值
        length_data=len(self.data_list)
        # （1 +Ti）的累和
        for index in range(length_data):
            res_t+=((self.get_ta(index)+1)*self.weight_list[index])
        select_sort=list(combinations(len(self.data_list),2))#二项式得到的每一个选择排列 eg [(5, 6), (5, 7), (5, 8), (6, 7), (6, 8), (7, 8)]
        select=iter(select_sort)
        value=self.two_add(next(select),res_t)
        for it in select:
            temp = self.two_add(it, res_t)
            value=self.multi(value,temp)
        return self.kmulti(value,1/(self.a+self.b))
class PowerBonferroniWA(Operator_IVQ_ROFS):
    def get_ta(self, i_a, *waste1, **waste2):
        """
            function : 计算 TA ，需要调用 get_sup
            i_a      : 传入模糊数 ai 的下标 int
            *waste1  : 回收多余的输入参数
            **waste2 : 回收多余的输入键值对参数
            return   : T(ai) 的值
            attention:此处带权重的计算公式，索引重写这个函数
        """
        ta = 0
        # T(ai) = 累加wi * Sup(ai, aj)
        for j_a in range(len(self.data_list)):
            if j_a != i_a:         # 公式要求 i != j
                ta += self.get_sup(self.data_list[i_a], self.data_list[j_a])*self.weight_list[i_a]
        return ta
    def two_multil(self,conbina:tuple,res_t=None):
        '''

        :param a1:  索引下标
        :param a2:  索引下标
        :param res_t: 1+Ti的累和结果
        :return: 两个模糊数的计算结果
        '''
        a1,a2=conbina
        A=self.a
        B=self.b
        n=len(self.data_list)
        if res_t is None:
            raise TypeError("res_t is NUll")
        res_a1=self.pow(self.kmulti(self.data_list[a1],(((1+self.get_ta(a1))*n*self.weight_list[a1])/res_t)),A)
        res_a2=self.pow(self.kmulti(self.data_list[a2],(((1+self.get_ta(a2))*n*self.weight_list[a2])/res_t)),B)
        return self.multi(res_a1,res_a2)



    def getResult(self):
        res_t=0 #储存 （1+Ti）累和的值
        length_data=len(self.data_list)
        # （1 +Ti）的累和
        for index in range(length_data):
            res_t+=((self.get_ta(index)+1)*self.weight_list[index])
        select_sort=list(combinations(len(self.data_list),2))#二项式得到的每一个选择排列 eg [(5, 6), (5, 7), (5, 8), (6, 7), (6, 8), (7, 8)]
        select=iter(select_sort)
        value=self.two_multil(next(select),res_t)
        for it in select:
            temp = self.two_multil(it, res_t)
            value=self.add(value,temp)
        return self.pow(self.kmulti(value,1/(length_data*length_data-length_data)),1/(self.a+self.b))
class PowerBonferroniOWA(Operator_IVQ_ROFS):
    def get_ta(self, i_a, *waste1, **waste2):
        """
            function : 计算 TA ，需要调用 get_sup
            i_a      : 传入模糊数 ai 的下标 int
            *waste1  : 回收多余的输入参数
            **waste2 : 回收多余的输入键值对参数
            return   : T(ai) 的值
            attention:此处带权重的计算公式，索引重写这个函数
        """
        ta = 0
        # T(ai) = 累加wi * Sup(ai, aj)
        for j_a in range(len(self.data_list)):
            if j_a != i_a:         # 公式要求 i != j
                ta += self.get_sup(self.data_list[i_a], self.data_list[j_a])*self.weight_list[i_a]
        return ta
    def two_multil(self,conbina:tuple,res_t=None):
        '''

        :param a1:  索引下标
        :param a2:  索引下标
        :param res_t: 1+Ti的累和结果
        :return: 两个模糊数的计算结果
        '''
        a1,a2=conbina
        A=self.a
        B=self.b
        n=len(self.data_list)
        if res_t is None:
            raise TypeError("res_t is NUll")
        res_a1=self.pow(self.kmulti(self.data_list[a1],(((1+self.get_ta(a1))*n*self.weight_list[a1])/res_t)),A)
        res_a2=self.pow(self.kmulti(self.data_list[a2],(((1+self.get_ta(a2))*n*self.weight_list[a2])/res_t)),B)
        return self.multi(res_a1,res_a2)



    def getResult(self):
        res_t=0 #储存 （1+Ti）累和的值
        temp_data=self.data_list
        self.data_list=self.sortdata()
        length_data = len(self.data_list)
        # （1 +Ti）的累和
        for index in range(length_data):
            res_t+=((self.get_ta(index)+1)*self.weight_list[index])
        select_sort=list(combinations(len(self.data_list),2))#二项式得到的每一个选择排列 eg [(5, 6), (5, 7), (5, 8), (6, 7), (6, 8), (7, 8)]
        select=iter(select_sort)
        value=self.two_multil(next(select),res_t)
        for it in select:
            temp = self.two_multil(it, res_t)
            value=self.add(value,temp)
        return self.pow(self.kmulti(value,1/(length_data*length_data-length_data)),1/(self.a+self.b))

















